package cn.dlc.com.config;

import cn.dlc.com.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author 邓立川
 * @date 2021/11/21 15:19
 * @desc 当前类的描述信息
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true, securedEnabled=true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

/*    // 如果有指定的UserDetailService的话，这个要注释掉
    @Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        // 内存里面创建了两个人
        userDetailsManager.createUser(User.withUsername("jack").password("{noop}123").authorities("p1").build());
        userDetailsManager.createUser(User.withUsername("rose").password("{noop}123").authorities("p2").build());
        return userDetailsManager;
    }*/

    @Autowired
    private UserService userService;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 这部分访问需要权限
                .antMatchers("/user/r/r1").hasAnyAuthority("p1")
                .antMatchers("/user/r/r2").hasAnyAuthority("p2")
                // 这部分需要认证（非这部分的不需要认证）
                .antMatchers("/user/r/**").authenticated()
                // access的使用
                .antMatchers("/test/r/**").access("hasRole('admin') and hasAnyAuthority('p1')")
                // 其他请求不做限制
                .anyRequest().permitAll()

                // 配置登录相关的信息，登录成功之后跳转到login-success
                .and().formLogin()
                // 自定义登录页
                .loginPage("/my-login")
                // springsecurity提供的登录方法
                .loginProcessingUrl("/login")
                // 成功之后的跳转页面
                .successForwardUrl("/user/login-success")
                // 配置登录成功之后的 handler，配置了之后 successForwardUrl 无效
                // .successHandler(null)
                // 允许所有用户访问登录页
                .permitAll()


                .and()
                .logout()
                // 指定退出的方法（SpringSecurity自己的方法）
                .logoutUrl("/logout")
                // 退出之后跳转的页面
                .logoutSuccessUrl("/user/logout-success")
                // 退出成功之后的handler(指定这个，logoutSuccessUrl会被忽略)
                // .logoutSuccessHandler(null)
                // 一般用来实现用户退出的清理工作，默认SecurityContextLogoutHandler会被添加为最后一个LogoutHandler
                // .addLogoutHandler()
                // 退出之后让session无效
                .invalidateHttpSession(true)


                // IF_REQUIRED 默认的方式，如果需要就使用session
                // always ： 如果没有session就创建一个
                // never：springsecurity不会创建session，但是如果其他地方创建了，security会使用
                // stateless：springsecurity不使用session，一般用token的时候指定这个
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
//                .and().csrf().disable()
                // 开启rememberMe
                .and().rememberMe()
                .alwaysRemember(true)
                // 指定userService
                .userDetailsService(userService)
                // 有效时间
                .tokenValiditySeconds(50)
        ;
    }

    // 这样可以放行静态文件
    public void configure(WebSecurity web) throws Exception{
        web.ignoring().mvcMatchers("/css/**","/img/**","/plugins/**");
    }

    // 配置认证用户的来源，内置用户信息（这个东西不配置也没问题啊！！！）
    /*protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());

        // 配置用户在内存里面
        auth.inMemoryAuthentication()
                .withUser("user")
                .password("{noop}user")
                // 查看源码这个角色是默认以ROLE_开头的
                .roles("USER");
    }*/
}
